﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.Collections;
using System.IO;

namespace ECGServer
{
    class ThreadHandleTCPConnection
    {
        IPEndPoint senderEndPoint;
        TcpClient client;
        NetworkStream stream;
        StreamReader sr;
        StreamWriter sw;

        public ThreadHandleTCPConnection(TcpClient client)
        {
            this.client = client;
            senderEndPoint = (IPEndPoint)client.Client.RemoteEndPoint;
            stream = client.GetStream();
            sr = new StreamReader(client.GetStream());
            sw = new StreamWriter(client.GetStream());
        }

        public void handleTCPConnection(object threadContext)
        {
            Console.WriteLine("*********************************************************************");
            string message = readFromStream(stream);
            handleMessgage(message);
        }

        public void handleMessgage(string message)
        {
            string[] s = message.Split('|');
            Console.WriteLine("Receive messgage {0} at {1}", s[0], DateTime.Now);
            switch (s[0])
            {
                case Constants.MSG_READYSEND:
                    Console.WriteLine("_____Ready send patient {0}", s[1]);
                    onReadySendMessage(s[1], s[2]);
                    break;
                case Constants.MSG_STOPSEND:
                    Console.WriteLine("_____Stop send patient {0} data", s[1]);
                    onStopSendMessage(s[1]);
                    break;
                case Constants.MSG_REQUESTDATA:
                    Console.WriteLine("_____From address: {0} request: {1}", senderEndPoint.Address, s[1]);
                    onRequestDataMessage(s[1]);
                    break;
                case Constants.MSG_STOPRECEIVE:
                    Console.WriteLine("_____From address: {0} stop receive from: {1}", senderEndPoint.Address, s[1]);
                    try
                    {
                        int id = Convert.ToInt32(s[2]);
                        onStopReceiveMessage(s[1], id);
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine("Message stop receive has wrong format");
                    }
                    break;
                case Constants.MSG_ALIVE:
                    Console.WriteLine("_____From address: {0}. Received message IamAlive Client : {1} id : {2}", 
                        senderEndPoint.Address, s[1], s[2]);
                    try
                    {
                        int id = Convert.ToInt32(s[2]);
                        lock (ECGServer.PID_Client)
                        {
                            Hashtable hashtable = (Hashtable)ECGServer.PID_Client[s[1]];
                            ((Client)hashtable[id]).LastCommunicationTime = System.DateTime.Now;
                        }
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine("_____Message IamAlive has wrong format");
                    }
                    break;
            }

            //Shutdown and end connection
            client.Close();
        }

        /*
         * Server is received "ReadySend" message from WS        
         */
        public void onReadySendMessage(string pID, string mark)
        {

            if (!ECGServer.PID_WorkStation.Contains(pID))
            {
                lock (ECGServer.PID_WorkStation)
                {
                    WorkStation ws = new WorkStation();
                    ws.LeadMark = mark;
                    ECGServer.PID_WorkStation.Add(pID, ws);
                }

                //Send message "OK" to workstation
                writeToStream(stream, Constants.MSG_OK);

                //Create a hashtalbe to store clients that want to take data
                Hashtable clientsHT = new Hashtable();
                ECGServer.PID_Client.Add(pID, clientsHT);
                Hashtable clientEndPointHT = new Hashtable();
                ECGServer.PID_ClientEndPoint.Add(pID, clientEndPointHT);
            }
            else
            {
                writeToStream(stream, Constants.MSG_EXISTING);
            }
        }

        /*
         *  Server is received "StopSend" message
         */
        public void onStopSendMessage(string pID)
        {
            if (ECGServer.PID_WorkStation.Contains(pID))
            {
                //Do not need to send message "StopSend" to clients. 
                //Clients knows to handle itself

                //Remove Workstation from PID_WorkStation
                lock (ECGServer.PID_WorkStation)
                {
                    ECGServer.PID_WorkStation.Remove(pID);
                }

                lock (ECGServer.PID_ClientEndPoint)
                {
                    ECGServer.PID_ClientEndPoint.Remove(pID);
                }

                //Remove hashtable from PID_Client
                lock (ECGServer.PID_Client)
                {
                    ECGServer.PID_Client.Remove(pID);
                }
            }
        }

        public void onRequestDataMessage(string pid)
        {
            if (ECGServer.PID_WorkStation.Contains(pid))
            {
                lock (ECGServer.PID_WorkStation)
                {
                    lock (ECGServer.PID_Client)
                    {
                        //Add new client to HashTable in PID_Client Hashtable
                        WorkStation ws = (WorkStation)ECGServer.PID_WorkStation[pid];
                        Hashtable clientHashTable = (Hashtable)ECGServer.PID_Client[pid];
                        int id = ws.ClientNumber++;
                        Client c = new Client(senderEndPoint);
                        c.ID = id;
                        clientHashTable.Add(id, c);
                        writeToStream(stream, Constants.MSG_OK + "|" + id + "|" + ws.LeadMark);
                        Console.WriteLine("_______Number of clients receive from {0}: {1}",
                            pid, clientHashTable.Keys.Count);
                    }
                }
            }
            else
            {
                writeToStream(stream, Constants.MSG_NOWORKSTATION);
            }
        }

        public void onStopReceiveMessage(string pid, int id)
        {
            if (ECGServer.PID_Client.Contains(pid))
            {
                lock (ECGServer.PID_Client)
                {
                    Hashtable clientHashTable = (Hashtable)ECGServer.PID_Client[pid];
                    clientHashTable.Remove(id);
                    Console.WriteLine("_______Number of clients receive from {0}: {1}",
                            pid, clientHashTable.Keys.Count);
                    //Do not need to send StopReceive to WorkStation
                }
            }
            if (ECGServer.PID_ClientEndPoint.Contains(pid))
            {
                lock (ECGServer.PID_ClientEndPoint)
                {
                    Hashtable clientEndPointHT = (Hashtable)ECGServer.PID_ClientEndPoint[pid];
                    clientEndPointHT.Remove(id);
                }
            }
        }

        public string readFromStream(NetworkStream stream)
        {
            byte[] bytes = new byte[256];
            int i = stream.Read(bytes, 0, bytes.Length);
            string s = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
            return s;
        }

        public void writeToStream(NetworkStream stream, String message)
        {
            byte[] bytes = Encoding.ASCII.GetBytes(message);
            stream.Write(bytes, 0, bytes.Length);
        }
    }
}
